library(tidyverse)
require("maps")
library(geosphere)
library(stringr)
library(rgdal)
library(caret)
library(lubridate)
library(maptools)
if (!require(ggmap)) { install.packages('ggmap'); require(ggmap) }
library(ggmap)
here_long <-  -122.3095
here_lat <- 47.6560
seattle = get_map(location = c(here_long, here_lat), zoom = 13, maptype = 'roadmap')
Map from URL : http://maps.googleapis.com/maps/api/staticmap?center=47.656,-122.3095&zoom=13&size=640x640&scale=2&maptype=roadmap&language=en-EN&sensor=false

Clustering crimes by Time of Day

Time is a huge factor when discussing pedestrian safety in an error, or so we’re told. Common wisdom states that night time is more dangerous than day time, but is this even true? When do crimes get reported, and how does that change where the centers of crime are located. Here we look at a year’s worth of SPD data in order to gain some insight.

data <- read.csv('../maps-api-test/2016-2017-Clean.csv', header = TRUE)
data <- filter(data, !str_detect(Event.Clearance.Description, "HARBOR - DEBRIS, NAVIGATIONAL HAZARDS"))
ggmap(seattle) +
   geom_point(data = data, aes(x = Longitude, y = Latitude), colour = "red", alpha = 0.75)

First of, we want to make sure we use as much data as possible. Using reports for all years tract would be ideal, but that data set is too large to handle easily. Instead, we’d like to use just the past year’s worth, from November 1st, 2016, all the way to October 31, 2017. That gives us a full year’s worth of data to look at, and its far enough in the past from today that we can ensure most, if not all, incidences will be closed (and therefore included in the data set).

Before we go any further though, it is important we determine whether or not the time of year has any meaningful effect on the number of observations we have to work with. If several months have much higher crime rates than others, it may skew results of any analysis we do. With that in mind, let’s take a look at the distribution of crimes for each month in the last year:

#check frequency by month
by.month <- table(data$event_clearance_month)
ggplot(as.data.frame(by.month), 
       aes(x = Var1, y = Freq)) +
       geom_bar(stat = 'identity') +
      labs(title = 'Crimes Reported In U-District, Nov. 2016 - Oct. 2017') +
      xlab('Month') +
      ylab('Number of Crimes Reported')

As we can see, there isn’t much varience in the frequency of reported crimes in our area for the past year. We can use a Kruskal-Wallis to test the independence of Month and Number of Crimes, which should indicate whether there is a relationship between them or not:

k <- kruskal.test(Freq ~ Var1, by.month)
k

    Kruskal-Wallis rank sum test

data:  Freq by Var1
Kruskal-Wallis chi-squared = 11, df = 11, p-value = 0.4433

Since our null hypothesis, that the count of crimes for each month is consistent, was given a p-value of 0.4433, we can confidently reject it and state that there is no dependence between the month of year and the number of crimes reported during it.

Next, we can look at the distribution of crimes across the categories we’ve defined. If there’s no variation there, we can continue to look at the data set as a whole, but if there’s significant variation, we’ll need to handle things a bit more carefully. Here we see a histogram of the Event Clearance Descriptions (what the reported crime was classified as in the SPD’s computer system.):

freq_by_desc <- table(droplevels(data$Event.Clearance.Description))
ggplot(as.data.frame(freq_by_desc), 
       aes(x = Var1, y = Freq)) +
       geom_bar(stat = 'identity') +
      xlab('Number of Crimes') +
      ylab('Crime Description') +
    coord_flip()

We see here that there is significant differences in the types of crimes that are reported, with Crisis Complaints comprising a large number of them. This could simply be due to a large number of mental health crisises in the U-District. More likely, however, officers are unsure of what to classify a crime as in an incident report and they simply choose a catch all category that comes closest to describing what happened. Regardless, this uneven distribution means that when it comes time to perform clustering, we’ll need to be careful to account for the significant weight these crimes will inflict upon the cluster centers.

#ggmap(seattle) +
#  geom_point(data = data, aes(x = Longitude, y = Latitude, group = Event.Clearance.Description, color = #Event.Clearance.Description), alpha = 0.5, size = 10) +
#  facet_wrap(~ Event.Clearance.Description) +
#  theme(axis.ticks = element_blank(), 
#        axis.text.x = element_blank(),
#        axis.text.y = element_blank(),
#        strip.text = element_text(size=50),
#        legend.position = "none"
#        )

These are some function that will help facilitate running k means clustering

#some useful functions for performing clustering
#extract the lat and long from a dataframe, and run kmeans on it
# x = one of our dataframes
# clusters = how many centers you want kmeans to work with when clustering
fit.clusters <- function(x, clusters) {
  # selecting just ID and location data
  df_loc <- x %>% dplyr::select(CAD.CDW.ID, Latitude, Longitude)
  # fitting model
  fit <- kmeans(df_loc, clusters)
  fit$centers # look at cluster sizes and means. want clusters to be about equal size
  return(fit)
}
#make a plot that will tell you how many clusters might work for a given dataframe
# x = a dataframe
# max = the maximum number of clusters you want to try
find.num.clusters <- function(x, max) {
  if(max > nrow(x)) { stop('Cannot fit more clusters than there are rows in dataframe')}
  df_loc <- x %>% dplyr::select(CAD.CDW.ID, Latitude, Longitude)
  wss = c()
  for (i in 1:max) {
    wss[i] <- sum(kmeans(df_loc, centers=i)$withinss)
  }
  plot(1:max, wss, type="b", xlab="Number of Clusters",
     ylab="Within groups sum of squares")
}
#plot the number of observations in each cluster
# x = a fit object returned from kmeans() or the fit.clusters() function above
plot.cluster.sizes <- function(x) {
  cluster.size <- data.frame(data.frame('clusters' = 1:nrow(x$centers), x$size))
  ggplot(data = cluster.size, aes(x = clusters, y = x.size)) +
  geom_bar(stat = 'identity')
}

We can bucket the data into 6 time frames to look at how reported crime changes throughout the day:

morning <- filter(data, 6 <= at_scene_time_hr, at_scene_time_hr < 10 )
mid.day <-  filter(data, 10 <= at_scene_time_hr, at_scene_time_hr < 14 )
afternoon <-  filter(data, 14 <= at_scene_time_hr, at_scene_time_hr < 18 )
evening <-  filter(data, 18 <= at_scene_time_hr, at_scene_time_hr < 22 )
night <-  filter(data, 22 <= at_scene_time_hr | at_scene_time_hr < 2 )
early.morning <-  filter(data, 2 <= at_scene_time_hr, at_scene_time_hr < 6 )
ggmap(seattle) +
  geom_point(data = morning, aes(x = Longitude, y = Latitude), alpha = 0.5) + 
  labs(title = 'Morning')

ggmap(seattle) +
  geom_point(data = mid.day, aes(x = Longitude, y = Latitude), alpha = 0.5) + 
  labs(title = 'Mid Day')

ggmap(seattle) +
  geom_point(data = afternoon, aes(x = Longitude, y = Latitude), alpha = 0.5) + 
  labs(title = 'Afternoon')

ggmap(seattle) +
  geom_point(data = evening, aes(x = Longitude, y = Latitude), alpha = 0.5) + 
  labs(title = 'Evening')

ggmap(seattle) +
  geom_point(data = night, aes(x = Longitude, y = Latitude), alpha = 0.5) + 
  labs(title = 'Night')

ggmap(seattle) +
  geom_point(data = early.morning, aes(x = Longitude, y = Latitude), alpha = 0.5) + 
  labs(title = 'Early Morning')

We can see that crimes reported are generally normally distributed around the afternoon. This would suggest that the highest rate of crime is during the day, or that there are less people reporting crimes at night. Which one is true isn’t possible to infer from this data.

lengths <- c(nrow(morning), nrow(mid.day), nrow(afternoon), nrow(evening), nrow(night), nrow(early.morning))
names <- c('Morning\n6:00 - 9:59', 'Mid-day\n10:00 - 1:59', 'Afternoon\n2:00 - 5:59', 'Evening\n6:00 - 9:59', 'Night\n10:00 - 1:59', 'Early Morning\n2:00 - 5:59')
by.tod <- data.frame('TOD' = names, 'Count.Crimes' = lengths)
by.tod$TOD = factor(by.tod$TOD, levels = by.tod$TOD)
ggplot(by.tod, aes(x = TOD, y = Count.Crimes)) +
  geom_histogram(stat = 'identity')
Ignoring unknown parameters: binwidth, bins, pad

Clustering reveals that the average reported crime doesn’t stay too far from the Ave. Some time frames have somewhat lower densities.

fit <- fit.clusters(morning, 10)
ggmap(seattle) +
  geom_point(data = as.data.frame(fit$centers), aes(x = Longitude, y = Latitude), alpha = 0.5)

plot.cluster.sizes(fit)

fit <- fit.clusters(mid.day, 10)
ggmap(seattle) +
  geom_point(data = as.data.frame(fit$centers), aes(x = Longitude, y = Latitude), alpha = 0.5)

plot.cluster.sizes(fit)

fit <- fit.clusters(afternoon, 10)
ggmap(seattle) +
  geom_point(data = as.data.frame(fit$centers), aes(x = Longitude, y = Latitude), alpha = 0.5)

plot.cluster.sizes(fit)

fit <- fit.clusters(evening, 10)
ggmap(seattle) +
  geom_point(data = as.data.frame(fit$centers), aes(x = Longitude, y = Latitude), alpha = 0.5)

plot.cluster.sizes(fit)

fit <- fit.clusters(night, 10)
ggmap(seattle) +
  geom_point(data = as.data.frame(fit$centers), aes(x = Longitude, y = Latitude), alpha = 0.5)

plot.cluster.sizes(fit)

The fact that Crisis Complaints outnumber every other description and its not very specific is skewing our analysis. Let’s remove those crimes and try again.

#take out general crisis complaint - general
data <- filter(data, Event.Clearance.Description != 'CRISIS COMPLAINT - GENERAL')
morning <- filter(data, 6 <= at_scene_time_hr, at_scene_time_hr < 10 )
mid.day <-  filter(data, 10 <= at_scene_time_hr, at_scene_time_hr < 14 )
afternoon <-  filter(data, 14 <= at_scene_time_hr, at_scene_time_hr < 18 )
evening <-  filter(data, 18 <= at_scene_time_hr, at_scene_time_hr < 22 )
night <-  filter(data, 22 <= at_scene_time_hr | at_scene_time_hr < 2 )
early.morning <-  filter(data, 2 <= at_scene_time_hr, at_scene_time_hr < 6 )
ggmap(seattle) +
  geom_point(data = morning, aes(x = Longitude, y = Latitude), alpha = 0.5) + 
  labs(title = 'Morning')

ggmap(seattle) +
  geom_point(data = mid.day, aes(x = Longitude, y = Latitude), alpha = 0.5) + 
  labs(title = 'Mid Day')

ggmap(seattle) +
  geom_point(data = afternoon, aes(x = Longitude, y = Latitude), alpha = 0.5) + 
  labs(title = 'Afternoon')

ggmap(seattle) +
  geom_point(data = evening, aes(x = Longitude, y = Latitude), alpha = 0.5) + 
  labs(title = 'Evening')

ggmap(seattle) +
  geom_point(data = night, aes(x = Longitude, y = Latitude), alpha = 0.5) + 
  labs(title = 'Night')

ggmap(seattle) +
  geom_point(data = early.morning, aes(x = Longitude, y = Latitude), alpha = 0.5) + 
  labs(title = 'Early Morning')

lengths <- c(nrow(morning), nrow(mid.day), nrow(afternoon), nrow(evening), nrow(night), nrow(early.morning))
names <- c('Morning\n6:00 - 9:59', 'Mid-day\n10:00 - 1:59', 'Afternoon\n2:00 - 5:59', 'Evening\n6:00 - 9:59', 'Night\n10:00 - 1:59', 'Early Morning\n2:00 - 5:59')
by.tod <- data.frame('TOD' = names, 'Count.Crimes' = lengths)
by.tod$TOD = factor(by.tod$TOD, levels = by.tod$TOD)
ggplot(by.tod, aes(x = TOD, y = Count.Crimes)) +
  geom_histogram(stat = 'identity')
Ignoring unknown parameters: binwidth, bins, pad

# find the mode of numeric/character data
Mode <- function(x) {
  ux <- unique(x)
  tab <- tabulate(match(x, ux)); ux[tab == max(tab)]
}
tod.mean <- mean(data$at_scene_time_hr)
tod.med <- median(data$at_scene_time_hr)
tod.mean
[1] 13.6691
tod.med
[1] 14
Mode(data$at_scene_time_hr)
[1] 17
#What is the most common crime committed at each period?
Mode(morning$Event.Clearance.Description)
[1] HAZARDS
7 Levels: ARMED ROBBERY CRISIS COMPLAINT - GENERAL FIGHT DISTURBANCE ... STRONG ARM ROBBERY
Mode(mid.day$Event.Clearance.Description)
[1] HARASSMENT, THREATS
7 Levels: ARMED ROBBERY CRISIS COMPLAINT - GENERAL FIGHT DISTURBANCE ... STRONG ARM ROBBERY
Mode(afternoon$Event.Clearance.Description)
[1] HARASSMENT, THREATS
7 Levels: ARMED ROBBERY CRISIS COMPLAINT - GENERAL FIGHT DISTURBANCE ... STRONG ARM ROBBERY
Mode(evening$Event.Clearance.Description)
[1] HARASSMENT, THREATS
7 Levels: ARMED ROBBERY CRISIS COMPLAINT - GENERAL FIGHT DISTURBANCE ... STRONG ARM ROBBERY
Mode(night$Event.Clearance.Description)
[1] HARASSMENT, THREATS
7 Levels: ARMED ROBBERY CRISIS COMPLAINT - GENERAL FIGHT DISTURBANCE ... STRONG ARM ROBBERY
Mode(early.morning$Event.Clearance.Description)
[1] STRONG ARM ROBBERY
7 Levels: ARMED ROBBERY CRISIS COMPLAINT - GENERAL FIGHT DISTURBANCE ... STRONG ARM ROBBERY
fit <- fit.clusters(morning, 10)
ggmap(seattle) +
  geom_point(data = as.data.frame(fit$centers), aes(x = Longitude, y = Latitude), alpha = 0.5)

plot.cluster.sizes(fit)

fit <- fit.clusters(mid.day, 10)
ggmap(seattle) +
  geom_point(data = as.data.frame(fit$centers), aes(x = Longitude, y = Latitude), alpha = 0.5)

plot.cluster.sizes(fit)

fit <- fit.clusters(afternoon, 10)
ggmap(seattle) +
  geom_point(data = as.data.frame(fit$centers), aes(x = Longitude, y = Latitude), alpha = 0.5)

plot.cluster.sizes(fit)

fit <- fit.clusters(evening, 10)
ggmap(seattle) +
  geom_point(data = as.data.frame(fit$centers), aes(x = Longitude, y = Latitude), alpha = 0.5)

plot.cluster.sizes(fit)

fit <- fit.clusters(night, 10)
ggmap(seattle) +
  geom_point(data = as.data.frame(fit$centers), aes(x = Longitude, y = Latitude), alpha = 0.5)

plot.cluster.sizes(fit)

LS0tCnRpdGxlOiAiUmVzdWx0cyIKb3V0cHV0OgogIHBkZl9kb2N1bWVudDogZGVmYXVsdAogIGh0bWxfbm90ZWJvb2s6IGRlZmF1bHQKLS0tCgpgYGB7ciBzZXR1cH0KbGlicmFyeSh0aWR5dmVyc2UpCnJlcXVpcmUoIm1hcHMiKQpsaWJyYXJ5KGdlb3NwaGVyZSkKbGlicmFyeShzdHJpbmdyKQpsaWJyYXJ5KHJnZGFsKQpsaWJyYXJ5KGNhcmV0KQpsaWJyYXJ5KGx1YnJpZGF0ZSkKbGlicmFyeShtYXB0b29scykKaWYgKCFyZXF1aXJlKGdnbWFwKSkgeyBpbnN0YWxsLnBhY2thZ2VzKCdnZ21hcCcpOyByZXF1aXJlKGdnbWFwKSB9CmxpYnJhcnkoZ2dtYXApCgpoZXJlX2xvbmcgPC0gIC0xMjIuMzA5NQpoZXJlX2xhdCA8LSA0Ny42NTYwCgpzZWF0dGxlID0gZ2V0X21hcChsb2NhdGlvbiA9IGMoaGVyZV9sb25nLCBoZXJlX2xhdCksIHpvb20gPSAxMywgbWFwdHlwZSA9ICdyb2FkbWFwJykKYGBgCiNDbHVzdGVyaW5nIGNyaW1lcyBieSBUaW1lIG9mIERheQoKVGltZSBpcyBhIGh1Z2UgZmFjdG9yIHdoZW4gZGlzY3Vzc2luZyBwZWRlc3RyaWFuIHNhZmV0eSBpbiBhbiBlcnJvciwgb3Igc28gd2UncmUgdG9sZC4gQ29tbW9uIHdpc2RvbSBzdGF0ZXMgdGhhdCBuaWdodCB0aW1lIGlzIG1vcmUgZGFuZ2Vyb3VzIHRoYW4gZGF5IHRpbWUsIGJ1dCBpcyB0aGlzIGV2ZW4gdHJ1ZT8gV2hlbiBkbyBjcmltZXMgZ2V0IHJlcG9ydGVkLCBhbmQgaG93IGRvZXMgdGhhdCBjaGFuZ2Ugd2hlcmUgdGhlIGNlbnRlcnMgb2YgY3JpbWUgYXJlIGxvY2F0ZWQuIEhlcmUgd2UgbG9vayBhdCBhIHllYXIncyB3b3J0aCBvZiBTUEQgZGF0YSBpbiBvcmRlciB0byBnYWluIHNvbWUgaW5zaWdodC4KCmBgYHtyfQpkYXRhIDwtIHJlYWQuY3N2KCcuLi9tYXBzLWFwaS10ZXN0LzIwMTYtMjAxNy1DbGVhbi5jc3YnLCBoZWFkZXIgPSBUUlVFKQpkYXRhIDwtIGZpbHRlcihkYXRhLCAhc3RyX2RldGVjdChFdmVudC5DbGVhcmFuY2UuRGVzY3JpcHRpb24sICJIQVJCT1IgLSBERUJSSVMsIE5BVklHQVRJT05BTCBIQVpBUkRTIikpCmdnbWFwKHNlYXR0bGUpICsKICAgZ2VvbV9wb2ludChkYXRhID0gZGF0YSwgYWVzKHggPSBMb25naXR1ZGUsIHkgPSBMYXRpdHVkZSksIGNvbG91ciA9ICJyZWQiLCBhbHBoYSA9IDAuNzUpCgpgYGAKCkZpcnN0IG9mLCB3ZSB3YW50IHRvIG1ha2Ugc3VyZSB3ZSB1c2UgYXMgbXVjaCBkYXRhIGFzIHBvc3NpYmxlLiBVc2luZyByZXBvcnRzIGZvciBhbGwgeWVhcnMgdHJhY3Qgd291bGQgYmUgaWRlYWwsIGJ1dCB0aGF0IGRhdGEgc2V0IGlzIHRvbyBsYXJnZSB0byBoYW5kbGUgZWFzaWx5LiBJbnN0ZWFkLCB3ZSdkIGxpa2UgdG8gdXNlIGp1c3QgdGhlIHBhc3QgeWVhcidzIHdvcnRoLCBmcm9tIE5vdmVtYmVyIDFzdCwgMjAxNiwgYWxsIHRoZSB3YXkgdG8gT2N0b2JlciAzMSwgMjAxNy4gVGhhdCBnaXZlcyB1cyBhIGZ1bGwgeWVhcidzIHdvcnRoIG9mIGRhdGEgdG8gbG9vayBhdCwgYW5kIGl0cyBmYXIgZW5vdWdoIGluIHRoZSBwYXN0IGZyb20gdG9kYXkgdGhhdCB3ZSBjYW4gZW5zdXJlIG1vc3QsIGlmIG5vdCBhbGwsIGluY2lkZW5jZXMgd2lsbCBiZSBjbG9zZWQgKGFuZCB0aGVyZWZvcmUgaW5jbHVkZWQgaW4gdGhlIGRhdGEgc2V0KS4KCkJlZm9yZSB3ZSBnbyBhbnkgZnVydGhlciB0aG91Z2gsIGl0IGlzIGltcG9ydGFudCB3ZSBkZXRlcm1pbmUgd2hldGhlciBvciBub3QgdGhlIHRpbWUgb2YgeWVhciBoYXMgYW55IG1lYW5pbmdmdWwgZWZmZWN0IG9uIHRoZSBudW1iZXIgb2Ygb2JzZXJ2YXRpb25zIHdlIGhhdmUgdG8gd29yayB3aXRoLiBJZiBzZXZlcmFsIG1vbnRocyBoYXZlIG11Y2ggaGlnaGVyIGNyaW1lIHJhdGVzIHRoYW4gb3RoZXJzLCBpdCBtYXkgc2tldyByZXN1bHRzIG9mIGFueSBhbmFseXNpcyB3ZSBkby4gV2l0aCB0aGF0IGluIG1pbmQsIGxldCdzIHRha2UgYSBsb29rIGF0IHRoZSBkaXN0cmlidXRpb24gb2YgY3JpbWVzIGZvciBlYWNoIG1vbnRoIGluIHRoZSBsYXN0IHllYXI6CgpgYGB7cn0KI2NoZWNrIGZyZXF1ZW5jeSBieSBtb250aApieS5tb250aCA8LSB0YWJsZShkYXRhJGV2ZW50X2NsZWFyYW5jZV9tb250aCkKZ2dwbG90KGFzLmRhdGEuZnJhbWUoYnkubW9udGgpLCAKICAgICAgIGFlcyh4ID0gVmFyMSwgeSA9IEZyZXEpKSArCiAgICAgICBnZW9tX2JhcihzdGF0ID0gJ2lkZW50aXR5JykgKwogICAgICBsYWJzKHRpdGxlID0gJ0NyaW1lcyBSZXBvcnRlZCBJbiBVLURpc3RyaWN0LCBOb3YuIDIwMTYgLSBPY3QuIDIwMTcnKSArCiAgICAgIHhsYWIoJ01vbnRoJykgKwogICAgICB5bGFiKCdOdW1iZXIgb2YgQ3JpbWVzIFJlcG9ydGVkJykKYGBgCkFzIHdlIGNhbiBzZWUsIHRoZXJlIGlzbid0IG11Y2ggdmFyaWVuY2UgaW4gdGhlIGZyZXF1ZW5jeSBvZiByZXBvcnRlZCBjcmltZXMgaW4gb3VyIGFyZWEgZm9yIHRoZSBwYXN0IHllYXIuIFdlIGNhbiB1c2UgYSBLcnVza2FsLVdhbGxpcyB0byB0ZXN0IHRoZSBpbmRlcGVuZGVuY2Ugb2YgTW9udGggYW5kIE51bWJlciBvZiBDcmltZXMsIHdoaWNoIHNob3VsZCBpbmRpY2F0ZSB3aGV0aGVyIHRoZXJlIGlzIGEgcmVsYXRpb25zaGlwIGJldHdlZW4gdGhlbSBvciBub3Q6CgpgYGB7cn0KayA8LSBrcnVza2FsLnRlc3QoRnJlcSB+IFZhcjEsIGJ5Lm1vbnRoKQprCmBgYAoKU2luY2Ugb3VyIG51bGwgaHlwb3RoZXNpcywgdGhhdCB0aGUgY291bnQgb2YgY3JpbWVzIGZvciBlYWNoIG1vbnRoIGlzIGNvbnNpc3RlbnQsIHdhcyBnaXZlbiBhIHAtdmFsdWUgb2YgMC40NDMzLCB3ZSBjYW4gY29uZmlkZW50bHkgcmVqZWN0IGl0IGFuZCBzdGF0ZSB0aGF0IHRoZXJlIGlzIG5vIGRlcGVuZGVuY2UgYmV0d2VlbiB0aGUgbW9udGggb2YgeWVhciBhbmQgdGhlIG51bWJlciBvZiBjcmltZXMgcmVwb3J0ZWQgZHVyaW5nIGl0LgoKCk5leHQsIHdlIGNhbiBsb29rIGF0IHRoZSBkaXN0cmlidXRpb24gb2YgY3JpbWVzIGFjcm9zcyB0aGUgY2F0ZWdvcmllcyB3ZSd2ZSBkZWZpbmVkLiBJZiB0aGVyZSdzIG5vIHZhcmlhdGlvbiB0aGVyZSwgd2UgY2FuIGNvbnRpbnVlIHRvIGxvb2sgYXQgdGhlIGRhdGEgc2V0IGFzIGEgd2hvbGUsIGJ1dCBpZiB0aGVyZSdzIHNpZ25pZmljYW50IHZhcmlhdGlvbiwgd2UnbGwgbmVlZCB0byBoYW5kbGUgdGhpbmdzIGEgYml0IG1vcmUgY2FyZWZ1bGx5LiBIZXJlIHdlIHNlZSBhIGhpc3RvZ3JhbSBvZiB0aGUgRXZlbnQgQ2xlYXJhbmNlIERlc2NyaXB0aW9ucyAod2hhdCB0aGUgcmVwb3J0ZWQgY3JpbWUgd2FzIGNsYXNzaWZpZWQgYXMgaW4gdGhlIFNQRCdzIGNvbXB1dGVyIHN5c3RlbS4pOgoKYGBge3J9CmZyZXFfYnlfZGVzYyA8LSB0YWJsZShkcm9wbGV2ZWxzKGRhdGEkRXZlbnQuQ2xlYXJhbmNlLkRlc2NyaXB0aW9uKSkKCmdncGxvdChhcy5kYXRhLmZyYW1lKGZyZXFfYnlfZGVzYyksIAogICAgICAgYWVzKHggPSBWYXIxLCB5ID0gRnJlcSkpICsKICAgICAgIGdlb21fYmFyKHN0YXQgPSAnaWRlbnRpdHknKSArCiAgICAgIHhsYWIoJ051bWJlciBvZiBDcmltZXMnKSArCiAgICAgIHlsYWIoJ0NyaW1lIERlc2NyaXB0aW9uJykgKwogICAgY29vcmRfZmxpcCgpCmBgYAoKV2Ugc2VlIGhlcmUgdGhhdCB0aGVyZSBpcyBzaWduaWZpY2FudCBkaWZmZXJlbmNlcyBpbiB0aGUgdHlwZXMgb2YgY3JpbWVzIHRoYXQgYXJlIHJlcG9ydGVkLCB3aXRoIENyaXNpcyBDb21wbGFpbnRzIGNvbXByaXNpbmcgYSBsYXJnZSBudW1iZXIgb2YgdGhlbS4gVGhpcyBjb3VsZCBzaW1wbHkgYmUgZHVlIHRvIGEgbGFyZ2UgbnVtYmVyIG9mIG1lbnRhbCBoZWFsdGggY3Jpc2lzZXMgaW4gdGhlIFUtRGlzdHJpY3QuIE1vcmUgbGlrZWx5LCBob3dldmVyLCBvZmZpY2VycyBhcmUgdW5zdXJlIG9mIHdoYXQgdG8gY2xhc3NpZnkgYSBjcmltZSBhcyBpbiBhbiBpbmNpZGVudCByZXBvcnQgYW5kIHRoZXkgc2ltcGx5IGNob29zZSBhIGNhdGNoIGFsbCBjYXRlZ29yeSB0aGF0IGNvbWVzIGNsb3Nlc3QgdG8gZGVzY3JpYmluZyB3aGF0IGhhcHBlbmVkLiBSZWdhcmRsZXNzLCB0aGlzIHVuZXZlbiBkaXN0cmlidXRpb24gbWVhbnMgdGhhdCB3aGVuIGl0IGNvbWVzIHRpbWUgdG8gcGVyZm9ybSBjbHVzdGVyaW5nLCB3ZSdsbCBuZWVkIHRvIGJlIGNhcmVmdWwgdG8gYWNjb3VudCBmb3IgdGhlIHNpZ25pZmljYW50IHdlaWdodCB0aGVzZSBjcmltZXMgd2lsbCBpbmZsaWN0IHVwb24gdGhlIGNsdXN0ZXIgY2VudGVycy4KCgpgYGB7ciBmaWcuaGVpZ2h0PTIwLCBmaWcud2lkdGg9MjB9CiNnZ21hcChzZWF0dGxlKSArCiMgIGdlb21fcG9pbnQoZGF0YSA9IGRhdGEsIGFlcyh4ID0gTG9uZ2l0dWRlLCB5ID0gTGF0aXR1ZGUsIGdyb3VwID0gRXZlbnQuQ2xlYXJhbmNlLkRlc2NyaXB0aW9uLCBjb2xvciA9ICNFdmVudC5DbGVhcmFuY2UuRGVzY3JpcHRpb24pLCBhbHBoYSA9IDAuNSwgc2l6ZSA9IDEwKSArCiMgIGZhY2V0X3dyYXAofiBFdmVudC5DbGVhcmFuY2UuRGVzY3JpcHRpb24pICsKIyAgdGhlbWUoYXhpcy50aWNrcyA9IGVsZW1lbnRfYmxhbmsoKSwgCiMgICAgICAgIGF4aXMudGV4dC54ID0gZWxlbWVudF9ibGFuaygpLAojICAgICAgICBheGlzLnRleHQueSA9IGVsZW1lbnRfYmxhbmsoKSwKIyAgICAgICAgc3RyaXAudGV4dCA9IGVsZW1lbnRfdGV4dChzaXplPTUwKSwKIyAgICAgICAgbGVnZW5kLnBvc2l0aW9uID0gIm5vbmUiCiMgICAgICAgICkKYGBgCgoKVGhlc2UgYXJlIHNvbWUgZnVuY3Rpb24gdGhhdCB3aWxsIGhlbHAgZmFjaWxpdGF0ZSBydW5uaW5nIGsgbWVhbnMgY2x1c3RlcmluZwpgYGB7cn0KI3NvbWUgdXNlZnVsIGZ1bmN0aW9ucyBmb3IgcGVyZm9ybWluZyBjbHVzdGVyaW5nCgojZXh0cmFjdCB0aGUgbGF0IGFuZCBsb25nIGZyb20gYSBkYXRhZnJhbWUsIGFuZCBydW4ga21lYW5zIG9uIGl0CiMgeCA9IG9uZSBvZiBvdXIgZGF0YWZyYW1lcwojIGNsdXN0ZXJzID0gaG93IG1hbnkgY2VudGVycyB5b3Ugd2FudCBrbWVhbnMgdG8gd29yayB3aXRoIHdoZW4gY2x1c3RlcmluZwpmaXQuY2x1c3RlcnMgPC0gZnVuY3Rpb24oeCwgY2x1c3RlcnMpIHsKICAjIHNlbGVjdGluZyBqdXN0IElEIGFuZCBsb2NhdGlvbiBkYXRhCiAgZGZfbG9jIDwtIHggJT4lIGRwbHlyOjpzZWxlY3QoQ0FELkNEVy5JRCwgTGF0aXR1ZGUsIExvbmdpdHVkZSkKCiAgIyBmaXR0aW5nIG1vZGVsCiAgZml0IDwtIGttZWFucyhkZl9sb2MsIGNsdXN0ZXJzKQogIGZpdCRjZW50ZXJzICMgbG9vayBhdCBjbHVzdGVyIHNpemVzIGFuZCBtZWFucy4gd2FudCBjbHVzdGVycyB0byBiZSBhYm91dCBlcXVhbCBzaXplCiAgcmV0dXJuKGZpdCkKfQoKI21ha2UgYSBwbG90IHRoYXQgd2lsbCB0ZWxsIHlvdSBob3cgbWFueSBjbHVzdGVycyBtaWdodCB3b3JrIGZvciBhIGdpdmVuIGRhdGFmcmFtZQojIHggPSBhIGRhdGFmcmFtZQojIG1heCA9IHRoZSBtYXhpbXVtIG51bWJlciBvZiBjbHVzdGVycyB5b3Ugd2FudCB0byB0cnkKZmluZC5udW0uY2x1c3RlcnMgPC0gZnVuY3Rpb24oeCwgbWF4KSB7CiAgaWYobWF4ID4gbnJvdyh4KSkgeyBzdG9wKCdDYW5ub3QgZml0IG1vcmUgY2x1c3RlcnMgdGhhbiB0aGVyZSBhcmUgcm93cyBpbiBkYXRhZnJhbWUnKX0KICBkZl9sb2MgPC0geCAlPiUgZHBseXI6OnNlbGVjdChDQUQuQ0RXLklELCBMYXRpdHVkZSwgTG9uZ2l0dWRlKQogIHdzcyA9IGMoKQogIGZvciAoaSBpbiAxOm1heCkgewogICAgd3NzW2ldIDwtIHN1bShrbWVhbnMoZGZfbG9jLCBjZW50ZXJzPWkpJHdpdGhpbnNzKQogIH0KICBwbG90KDE6bWF4LCB3c3MsIHR5cGU9ImIiLCB4bGFiPSJOdW1iZXIgb2YgQ2x1c3RlcnMiLAogICAgIHlsYWI9IldpdGhpbiBncm91cHMgc3VtIG9mIHNxdWFyZXMiKQp9CgojcGxvdCB0aGUgbnVtYmVyIG9mIG9ic2VydmF0aW9ucyBpbiBlYWNoIGNsdXN0ZXIKIyB4ID0gYSBmaXQgb2JqZWN0IHJldHVybmVkIGZyb20ga21lYW5zKCkgb3IgdGhlIGZpdC5jbHVzdGVycygpIGZ1bmN0aW9uIGFib3ZlCnBsb3QuY2x1c3Rlci5zaXplcyA8LSBmdW5jdGlvbih4KSB7CiAgY2x1c3Rlci5zaXplIDwtIGRhdGEuZnJhbWUoZGF0YS5mcmFtZSgnY2x1c3RlcnMnID0gMTpucm93KHgkY2VudGVycyksIHgkc2l6ZSkpCiAgZ2dwbG90KGRhdGEgPSBjbHVzdGVyLnNpemUsIGFlcyh4ID0gY2x1c3RlcnMsIHkgPSB4LnNpemUpKSArCiAgZ2VvbV9iYXIoc3RhdCA9ICdpZGVudGl0eScpCn0KYGBgCgpXZSBjYW4gYnVja2V0IHRoZSBkYXRhIGludG8gNiB0aW1lIGZyYW1lcyB0byBsb29rIGF0IGhvdyByZXBvcnRlZCBjcmltZSBjaGFuZ2VzIHRocm91Z2hvdXQgdGhlIGRheToKYGBge3J9Cm1vcm5pbmcgPC0gZmlsdGVyKGRhdGEsIDYgPD0gYXRfc2NlbmVfdGltZV9ociwgYXRfc2NlbmVfdGltZV9ociA8IDEwICkKbWlkLmRheSA8LSAgZmlsdGVyKGRhdGEsIDEwIDw9IGF0X3NjZW5lX3RpbWVfaHIsIGF0X3NjZW5lX3RpbWVfaHIgPCAxNCApCmFmdGVybm9vbiA8LSAgZmlsdGVyKGRhdGEsIDE0IDw9IGF0X3NjZW5lX3RpbWVfaHIsIGF0X3NjZW5lX3RpbWVfaHIgPCAxOCApCmV2ZW5pbmcgPC0gIGZpbHRlcihkYXRhLCAxOCA8PSBhdF9zY2VuZV90aW1lX2hyLCBhdF9zY2VuZV90aW1lX2hyIDwgMjIgKQpuaWdodCA8LSAgZmlsdGVyKGRhdGEsIDIyIDw9IGF0X3NjZW5lX3RpbWVfaHIgfCBhdF9zY2VuZV90aW1lX2hyIDwgMiApCmVhcmx5Lm1vcm5pbmcgPC0gIGZpbHRlcihkYXRhLCAyIDw9IGF0X3NjZW5lX3RpbWVfaHIsIGF0X3NjZW5lX3RpbWVfaHIgPCA2ICkKCmdnbWFwKHNlYXR0bGUpICsKICBnZW9tX3BvaW50KGRhdGEgPSBtb3JuaW5nLCBhZXMoeCA9IExvbmdpdHVkZSwgeSA9IExhdGl0dWRlKSwgYWxwaGEgPSAwLjUpICsgCiAgbGFicyh0aXRsZSA9ICdNb3JuaW5nJykKCmdnbWFwKHNlYXR0bGUpICsKICBnZW9tX3BvaW50KGRhdGEgPSBtaWQuZGF5LCBhZXMoeCA9IExvbmdpdHVkZSwgeSA9IExhdGl0dWRlKSwgYWxwaGEgPSAwLjUpICsgCiAgbGFicyh0aXRsZSA9ICdNaWQgRGF5JykKCmdnbWFwKHNlYXR0bGUpICsKICBnZW9tX3BvaW50KGRhdGEgPSBhZnRlcm5vb24sIGFlcyh4ID0gTG9uZ2l0dWRlLCB5ID0gTGF0aXR1ZGUpLCBhbHBoYSA9IDAuNSkgKyAKICBsYWJzKHRpdGxlID0gJ0FmdGVybm9vbicpCgpnZ21hcChzZWF0dGxlKSArCiAgZ2VvbV9wb2ludChkYXRhID0gZXZlbmluZywgYWVzKHggPSBMb25naXR1ZGUsIHkgPSBMYXRpdHVkZSksIGFscGhhID0gMC41KSArIAogIGxhYnModGl0bGUgPSAnRXZlbmluZycpCgpnZ21hcChzZWF0dGxlKSArCiAgZ2VvbV9wb2ludChkYXRhID0gbmlnaHQsIGFlcyh4ID0gTG9uZ2l0dWRlLCB5ID0gTGF0aXR1ZGUpLCBhbHBoYSA9IDAuNSkgKyAKICBsYWJzKHRpdGxlID0gJ05pZ2h0JykKCmdnbWFwKHNlYXR0bGUpICsKICBnZW9tX3BvaW50KGRhdGEgPSBlYXJseS5tb3JuaW5nLCBhZXMoeCA9IExvbmdpdHVkZSwgeSA9IExhdGl0dWRlKSwgYWxwaGEgPSAwLjUpICsgCiAgbGFicyh0aXRsZSA9ICdFYXJseSBNb3JuaW5nJykKYGBgCgpXZSBjYW4gc2VlIHRoYXQgY3JpbWVzIHJlcG9ydGVkIGFyZSBnZW5lcmFsbHkgbm9ybWFsbHkgZGlzdHJpYnV0ZWQgYXJvdW5kIHRoZSBhZnRlcm5vb24uIFRoaXMgd291bGQgc3VnZ2VzdCB0aGF0IHRoZSBoaWdoZXN0IHJhdGUgb2YgY3JpbWUgaXMgZHVyaW5nIHRoZSBkYXksIG9yIHRoYXQgdGhlcmUgYXJlIGxlc3MgcGVvcGxlIHJlcG9ydGluZyBjcmltZXMgYXQgbmlnaHQuIFdoaWNoIG9uZSBpcyB0cnVlIGlzbid0IHBvc3NpYmxlIHRvIGluZmVyIGZyb20gdGhpcyBkYXRhLgoKYGBge3J9Cmxlbmd0aHMgPC0gYyhucm93KG1vcm5pbmcpLCBucm93KG1pZC5kYXkpLCBucm93KGFmdGVybm9vbiksIG5yb3coZXZlbmluZyksIG5yb3cobmlnaHQpLCBucm93KGVhcmx5Lm1vcm5pbmcpKQpuYW1lcyA8LSBjKCdNb3JuaW5nXG42OjAwIC0gOTo1OScsICdNaWQtZGF5XG4xMDowMCAtIDE6NTknLCAnQWZ0ZXJub29uXG4yOjAwIC0gNTo1OScsICdFdmVuaW5nXG42OjAwIC0gOTo1OScsICdOaWdodFxuMTA6MDAgLSAxOjU5JywgJ0Vhcmx5IE1vcm5pbmdcbjI6MDAgLSA1OjU5JykKYnkudG9kIDwtIGRhdGEuZnJhbWUoJ1RPRCcgPSBuYW1lcywgJ0NvdW50LkNyaW1lcycgPSBsZW5ndGhzKQpieS50b2QkVE9EID0gZmFjdG9yKGJ5LnRvZCRUT0QsIGxldmVscyA9IGJ5LnRvZCRUT0QpCgpnZ3Bsb3QoYnkudG9kLCBhZXMoeCA9IFRPRCwgeSA9IENvdW50LkNyaW1lcykpICsKICBnZW9tX2hpc3RvZ3JhbShzdGF0ID0gJ2lkZW50aXR5JykKYGBgCgpDbHVzdGVyaW5nIHJldmVhbHMgdGhhdCB0aGUgYXZlcmFnZSByZXBvcnRlZCBjcmltZSBkb2Vzbid0IHN0YXkgdG9vIGZhciBmcm9tIHRoZSBBdmUuIFNvbWUgdGltZSBmcmFtZXMgaGF2ZSBzb21ld2hhdCBsb3dlciBkZW5zaXRpZXMuCgpgYGB7cn0KZml0IDwtIGZpdC5jbHVzdGVycyhtb3JuaW5nLCAxMCkKZ2dtYXAoc2VhdHRsZSkgKwogIGdlb21fcG9pbnQoZGF0YSA9IGFzLmRhdGEuZnJhbWUoZml0JGNlbnRlcnMpLCBhZXMoeCA9IExvbmdpdHVkZSwgeSA9IExhdGl0dWRlKSwgYWxwaGEgPSAwLjUpCnBsb3QuY2x1c3Rlci5zaXplcyhmaXQpCgpmaXQgPC0gZml0LmNsdXN0ZXJzKG1pZC5kYXksIDEwKQpnZ21hcChzZWF0dGxlKSArCiAgZ2VvbV9wb2ludChkYXRhID0gYXMuZGF0YS5mcmFtZShmaXQkY2VudGVycyksIGFlcyh4ID0gTG9uZ2l0dWRlLCB5ID0gTGF0aXR1ZGUpLCBhbHBoYSA9IDAuNSkKcGxvdC5jbHVzdGVyLnNpemVzKGZpdCkKCmZpdCA8LSBmaXQuY2x1c3RlcnMoYWZ0ZXJub29uLCAxMCkKZ2dtYXAoc2VhdHRsZSkgKwogIGdlb21fcG9pbnQoZGF0YSA9IGFzLmRhdGEuZnJhbWUoZml0JGNlbnRlcnMpLCBhZXMoeCA9IExvbmdpdHVkZSwgeSA9IExhdGl0dWRlKSwgYWxwaGEgPSAwLjUpCnBsb3QuY2x1c3Rlci5zaXplcyhmaXQpCgpmaXQgPC0gZml0LmNsdXN0ZXJzKGV2ZW5pbmcsIDEwKQpnZ21hcChzZWF0dGxlKSArCiAgZ2VvbV9wb2ludChkYXRhID0gYXMuZGF0YS5mcmFtZShmaXQkY2VudGVycyksIGFlcyh4ID0gTG9uZ2l0dWRlLCB5ID0gTGF0aXR1ZGUpLCBhbHBoYSA9IDAuNSkKcGxvdC5jbHVzdGVyLnNpemVzKGZpdCkKCmZpdCA8LSBmaXQuY2x1c3RlcnMobmlnaHQsIDEwKQpnZ21hcChzZWF0dGxlKSArCiAgZ2VvbV9wb2ludChkYXRhID0gYXMuZGF0YS5mcmFtZShmaXQkY2VudGVycyksIGFlcyh4ID0gTG9uZ2l0dWRlLCB5ID0gTGF0aXR1ZGUpLCBhbHBoYSA9IDAuNSkKcGxvdC5jbHVzdGVyLnNpemVzKGZpdCkKYGBgCgpUaGUgZmFjdCB0aGF0IENyaXNpcyBDb21wbGFpbnRzIG91dG51bWJlciBldmVyeSBvdGhlciBkZXNjcmlwdGlvbiBhbmQgaXRzIG5vdCB2ZXJ5IHNwZWNpZmljIGlzIHNrZXdpbmcgb3VyIGFuYWx5c2lzLiBMZXQncyByZW1vdmUgdGhvc2UgY3JpbWVzIGFuZCB0cnkgYWdhaW4uCgpgYGB7cn0KI3Rha2Ugb3V0IGdlbmVyYWwgY3Jpc2lzIGNvbXBsYWludCAtIGdlbmVyYWwKZGF0YSA8LSBmaWx0ZXIoZGF0YSwgRXZlbnQuQ2xlYXJhbmNlLkRlc2NyaXB0aW9uICE9ICdDUklTSVMgQ09NUExBSU5UIC0gR0VORVJBTCcpCgptb3JuaW5nIDwtIGZpbHRlcihkYXRhLCA2IDw9IGF0X3NjZW5lX3RpbWVfaHIsIGF0X3NjZW5lX3RpbWVfaHIgPCAxMCApCm1pZC5kYXkgPC0gIGZpbHRlcihkYXRhLCAxMCA8PSBhdF9zY2VuZV90aW1lX2hyLCBhdF9zY2VuZV90aW1lX2hyIDwgMTQgKQphZnRlcm5vb24gPC0gIGZpbHRlcihkYXRhLCAxNCA8PSBhdF9zY2VuZV90aW1lX2hyLCBhdF9zY2VuZV90aW1lX2hyIDwgMTggKQpldmVuaW5nIDwtICBmaWx0ZXIoZGF0YSwgMTggPD0gYXRfc2NlbmVfdGltZV9ociwgYXRfc2NlbmVfdGltZV9ociA8IDIyICkKbmlnaHQgPC0gIGZpbHRlcihkYXRhLCAyMiA8PSBhdF9zY2VuZV90aW1lX2hyIHwgYXRfc2NlbmVfdGltZV9ociA8IDIgKQplYXJseS5tb3JuaW5nIDwtICBmaWx0ZXIoZGF0YSwgMiA8PSBhdF9zY2VuZV90aW1lX2hyLCBhdF9zY2VuZV90aW1lX2hyIDwgNiApCgpnZ21hcChzZWF0dGxlKSArCiAgZ2VvbV9wb2ludChkYXRhID0gbW9ybmluZywgYWVzKHggPSBMb25naXR1ZGUsIHkgPSBMYXRpdHVkZSksIGFscGhhID0gMC41KSArIAogIGxhYnModGl0bGUgPSAnTW9ybmluZycpCgpnZ21hcChzZWF0dGxlKSArCiAgZ2VvbV9wb2ludChkYXRhID0gbWlkLmRheSwgYWVzKHggPSBMb25naXR1ZGUsIHkgPSBMYXRpdHVkZSksIGFscGhhID0gMC41KSArIAogIGxhYnModGl0bGUgPSAnTWlkIERheScpCgpnZ21hcChzZWF0dGxlKSArCiAgZ2VvbV9wb2ludChkYXRhID0gYWZ0ZXJub29uLCBhZXMoeCA9IExvbmdpdHVkZSwgeSA9IExhdGl0dWRlKSwgYWxwaGEgPSAwLjUpICsgCiAgbGFicyh0aXRsZSA9ICdBZnRlcm5vb24nKQoKZ2dtYXAoc2VhdHRsZSkgKwogIGdlb21fcG9pbnQoZGF0YSA9IGV2ZW5pbmcsIGFlcyh4ID0gTG9uZ2l0dWRlLCB5ID0gTGF0aXR1ZGUpLCBhbHBoYSA9IDAuNSkgKyAKICBsYWJzKHRpdGxlID0gJ0V2ZW5pbmcnKQoKZ2dtYXAoc2VhdHRsZSkgKwogIGdlb21fcG9pbnQoZGF0YSA9IG5pZ2h0LCBhZXMoeCA9IExvbmdpdHVkZSwgeSA9IExhdGl0dWRlKSwgYWxwaGEgPSAwLjUpICsgCiAgbGFicyh0aXRsZSA9ICdOaWdodCcpCgpnZ21hcChzZWF0dGxlKSArCiAgZ2VvbV9wb2ludChkYXRhID0gZWFybHkubW9ybmluZywgYWVzKHggPSBMb25naXR1ZGUsIHkgPSBMYXRpdHVkZSksIGFscGhhID0gMC41KSArIAogIGxhYnModGl0bGUgPSAnRWFybHkgTW9ybmluZycpCgpsZW5ndGhzIDwtIGMobnJvdyhtb3JuaW5nKSwgbnJvdyhtaWQuZGF5KSwgbnJvdyhhZnRlcm5vb24pLCBucm93KGV2ZW5pbmcpLCBucm93KG5pZ2h0KSwgbnJvdyhlYXJseS5tb3JuaW5nKSkKbmFtZXMgPC0gYygnTW9ybmluZ1xuNjowMCAtIDk6NTknLCAnTWlkLWRheVxuMTA6MDAgLSAxOjU5JywgJ0FmdGVybm9vblxuMjowMCAtIDU6NTknLCAnRXZlbmluZ1xuNjowMCAtIDk6NTknLCAnTmlnaHRcbjEwOjAwIC0gMTo1OScsICdFYXJseSBNb3JuaW5nXG4yOjAwIC0gNTo1OScpCmJ5LnRvZCA8LSBkYXRhLmZyYW1lKCdUT0QnID0gbmFtZXMsICdDb3VudC5DcmltZXMnID0gbGVuZ3RocykKYnkudG9kJFRPRCA9IGZhY3RvcihieS50b2QkVE9ELCBsZXZlbHMgPSBieS50b2QkVE9EKQoKZ2dwbG90KGJ5LnRvZCwgYWVzKHggPSBUT0QsIHkgPSBDb3VudC5DcmltZXMpKSArCiAgZ2VvbV9oaXN0b2dyYW0oc3RhdCA9ICdpZGVudGl0eScpCgojIGZpbmQgdGhlIG1vZGUgb2YgbnVtZXJpYy9jaGFyYWN0ZXIgZGF0YQpNb2RlIDwtIGZ1bmN0aW9uKHgpIHsKICB1eCA8LSB1bmlxdWUoeCkKICB0YWIgPC0gdGFidWxhdGUobWF0Y2goeCwgdXgpKTsgdXhbdGFiID09IG1heCh0YWIpXQp9Cgp0b2QubWVhbiA8LSBtZWFuKGRhdGEkYXRfc2NlbmVfdGltZV9ocikKdG9kLm1lZCA8LSBtZWRpYW4oZGF0YSRhdF9zY2VuZV90aW1lX2hyKQp0b2QubWVhbgp0b2QubWVkCk1vZGUoZGF0YSRhdF9zY2VuZV90aW1lX2hyKQoKI1doYXQgaXMgdGhlIG1vc3QgY29tbW9uIGNyaW1lIGNvbW1pdHRlZCBhdCBlYWNoIHBlcmlvZD8KTW9kZShtb3JuaW5nJEV2ZW50LkNsZWFyYW5jZS5EZXNjcmlwdGlvbikKTW9kZShtaWQuZGF5JEV2ZW50LkNsZWFyYW5jZS5EZXNjcmlwdGlvbikKTW9kZShhZnRlcm5vb24kRXZlbnQuQ2xlYXJhbmNlLkRlc2NyaXB0aW9uKQpNb2RlKGV2ZW5pbmckRXZlbnQuQ2xlYXJhbmNlLkRlc2NyaXB0aW9uKQpNb2RlKG5pZ2h0JEV2ZW50LkNsZWFyYW5jZS5EZXNjcmlwdGlvbikKTW9kZShlYXJseS5tb3JuaW5nJEV2ZW50LkNsZWFyYW5jZS5EZXNjcmlwdGlvbikKCmZpdCA8LSBmaXQuY2x1c3RlcnMobW9ybmluZywgMTApCmdnbWFwKHNlYXR0bGUpICsKICBnZW9tX3BvaW50KGRhdGEgPSBhcy5kYXRhLmZyYW1lKGZpdCRjZW50ZXJzKSwgYWVzKHggPSBMb25naXR1ZGUsIHkgPSBMYXRpdHVkZSksIGFscGhhID0gMC41KQpwbG90LmNsdXN0ZXIuc2l6ZXMoZml0KQoKZml0IDwtIGZpdC5jbHVzdGVycyhtaWQuZGF5LCAxMCkKZ2dtYXAoc2VhdHRsZSkgKwogIGdlb21fcG9pbnQoZGF0YSA9IGFzLmRhdGEuZnJhbWUoZml0JGNlbnRlcnMpLCBhZXMoeCA9IExvbmdpdHVkZSwgeSA9IExhdGl0dWRlKSwgYWxwaGEgPSAwLjUpCnBsb3QuY2x1c3Rlci5zaXplcyhmaXQpCgpmaXQgPC0gZml0LmNsdXN0ZXJzKGFmdGVybm9vbiwgMTApCmdnbWFwKHNlYXR0bGUpICsKICBnZW9tX3BvaW50KGRhdGEgPSBhcy5kYXRhLmZyYW1lKGZpdCRjZW50ZXJzKSwgYWVzKHggPSBMb25naXR1ZGUsIHkgPSBMYXRpdHVkZSksIGFscGhhID0gMC41KQpwbG90LmNsdXN0ZXIuc2l6ZXMoZml0KQoKZml0IDwtIGZpdC5jbHVzdGVycyhldmVuaW5nLCAxMCkKZ2dtYXAoc2VhdHRsZSkgKwogIGdlb21fcG9pbnQoZGF0YSA9IGFzLmRhdGEuZnJhbWUoZml0JGNlbnRlcnMpLCBhZXMoeCA9IExvbmdpdHVkZSwgeSA9IExhdGl0dWRlKSwgYWxwaGEgPSAwLjUpCnBsb3QuY2x1c3Rlci5zaXplcyhmaXQpCgpmaXQgPC0gZml0LmNsdXN0ZXJzKG5pZ2h0LCAxMCkKZ2dtYXAoc2VhdHRsZSkgKwogIGdlb21fcG9pbnQoZGF0YSA9IGFzLmRhdGEuZnJhbWUoZml0JGNlbnRlcnMpLCBhZXMoeCA9IExvbmdpdHVkZSwgeSA9IExhdGl0dWRlKSwgYWxwaGEgPSAwLjUpCnBsb3QuY2x1c3Rlci5zaXplcyhmaXQpCmBgYAoK